ELEC2142
__TOC__ Course This page is for the course ELEC2142 - Embedded Systems Design. The course is typically taken during session 2 by second years as a continuation in digital logic systems and an introduction to embedded software/hardware devices. Overview :An introduction to programmer model of computer organisation using assembly and machine language. Process of translation from high-level language to machine instructions. Number representation, computer arithmetic, instruction set architecture, I/O interfacing, I/O interrupts, programming interrupts, exceptions and their support in architecture. Memory management and protection and their support in architecture, the role of OS in handling exceptions. Multi-tasking and multi-threading environments. Use of interrupts for sampling, link-lists and circular buffers. D/A and A/D conversion and interfacing to the real physical world. Appreciation of the concepts learnt in the deployment of real-time systems. :''-- UNSW Handbook 2009'' Prerequisites Students undertaking this course are required to have completed ELEC2141 and COMP1921/7. Topics * ARM/Thumb Assembly Language * Interrupts * Exceptions * System Calls Old Lab notes ELEC2042 Laboratory Notebook ='Exercise 2.1 – A Simple Non-Real-Time Clock'= Initially, usleep was set to have a resolution 1s. The performance of the clock was accurate. I then tested for a resolution of 100s and 500s. As the resolution was increased, I found the clock to run less accurately, that is, the clock ran slower. For a high resolution, the while loop is being invoked more in a given space of time compared to a slow resolution. This means more calculations for the CPU. These calculations are given lesser priority over other processes in the kernel because we are not using RT-Linux. As a result, the specified resolution is not strictly adhered to, and the clock runs slower. ='Exercise 2.2 – A Graphical Non-Real-Time Clock'= Firstly, I ran “clock”, “clock-tens”, and “clock-hundreds” separately. They did not all run on time. This is because of their different resolutions. More calculations are required for higher resolutions in a given space of time, as explained in Exercise 2,1. “clock” was the fastest, followed by “clock-tens”, followed by “clock-hundreds”. When “clock”, “clock-tens”, and “clock-hundreds” were run together, once again “clock” was the fastest, followed by “clock-tens”, followed by “clock-hundreds”. However, their individual times were slower than when they were run separately. This is because the CPU has to deal with calculations of all three programs at once, which is a greater load on the CPU. Exercise 2.3 – Constructing a Real-Time Thread *I used the following counter code to implement a counter in a real-time thread: #define PERIOD 1000000 void *counter_code(void *arg) {'' ''int count =0; while(1) {'' ''pthread_wait_np( ); count = count +1; rtl_printf(“The counter has reached %d/n”, count); }'' ''} *''pthread_wait_np( )'' tells the kernel to wait until the time defined by PERIOD has surpassed before executing again. *I found when PERIOD is a large value, the program is as slow as Exercise 2.2 with a high resolution. ='Exercise 2.4 – Using Shared Memory'= *In both the linux and real-time code, I made sure to define volatile int count*; as a global variable. *In the linux main( ) function I added: count=(volatile int*)mbuff_alloc(“mycount”, 4); printf(“%d\n”, *count); *In the real-time code I added: count =(volatile int*)mbuff_alloc("mycount",4); inside init_module( ) mbuff_free("mycount",(void*)variable); inside cleanup_module( ) *count++ inside counter_code( ) ='Exercise 2.5 – Real-Time Digital Clock Operation'= *I defined the global variables tminutes, tseconds, uminutes, useconds ''in “rtclock.c” and created another file called “rttimer.c”. *''mbuff_alloc ''does the memory allocation. *It is clear from the real-time code that ''count++ increments by 1 every 1/100s (starting from 1s). *When 1s has passed (if count = =100), count must reset to 0. *The command rtl_printf is a real-time specific command and is used to display the clock. *A flag is set by the timer every second while it is being reset by the idle ''function. *Count must be made to run slower so rtclock can be reset to 0. *Linux has its memory space protected by a memory barrier. To communicate with real-time threads, shared memory must be used. '''Essential Components for this module' *''filter.c'' - Sets up the digital filter GUI. Allows you to change the coefficients of the discrete-time transfer function and its input (step, impulse or sinusoid). *''rtfilter.c'' - Creates a real-time thread for the digital filter, which calculates the digital filter output in real-time. Calculations depend on inputs to the GUI, which are communicated to rtfilter.c through shared memory. *''Vxscope –'' A non real-time program that plots the output of the digital filter. Exercise 2.1 PART 1 A The TF of the digital filter is represented as the data structure typedef struct dig_filter {.....} dig_fil; inside “filter.h”. B The input and ouput data sequences are stored within dig_fil. The input sequence is float uMAXSIZE; and the output sequence is float yMAXSIZE;. “''rtfilter.c” uses pointers to store the input and output data in real-time. C The filter implementation algorithm is run under ''int filter_run (void) in “rtfilter.c”. D GUI interacts with the code via gui.c. *The way the digital filter program components interact can be described by the following flow chart: PART 2 *When running the program, a''0'' is always 1, -2<=''a'1''<=2, -2<=''a'2''<=2, -1<=''a'3''<=1 *The numerator is the input, and denominator is the output. *-1<=''b'0''<=3, -1<=''b'1''<=1, -1<=''b'2''<=1, and -1<=''b'3''<=1. *The manual filter input is -10<=''f''<=10. Step sets the input to 1, and impulse sets the input to 0. I observed a fast sinusoid. PART 3 *The CDSM package can only store integers. For it to use a value such as 0.001, the real-time thread multiplies the data by 1000 before sharing it with CDSM. PART 5 i This is marginally stable, that is, it is oscillatory but bounded. This is expected because the poles of the TF lie on the unit circle, which is the criterion for marginal stability. ii This is stable. The output asymptotes towards 0. The pole of the TF lies within the unit circle, which is the criterion for stability. iii Stable like ii. iv Stable like ii. *If the numerator coefficients are divided by the sum of the denominator coefficients, then the inputs are changed. *Multiplying the numerator coefficients by 2 does not affect stability, but the step and impulse responses to increase in magnitude. PART 6 *Use phase = dt/T and gain = (output amplitude)/(input amplitude). '''Exercise 2.2 *Modified code is compiled using the make. *As the maximum input coefficient is only 2/3, MAXSIZE only needs to be of size 5. *Following is the modified filter code that makes storage in the existing buffer circular: int filter_non(void) {'' ''// The following code resets the head to zero '' ''df->time+ =1; if ((df->head)>(MAXSIZE –1)) {'' ''df->head = 0; }'' ''else df->head+ = 1; // The following code updates the input if(df->input_type = = 0) {'' ''if(df->head>0) df->u(df->head) = df->u(df->head); else df->u(df->head)=df->u(MAXSIZE); }'' ''// For the numerator in the difference equation for (i=0; ic=df->m, i++) {'' ''if((df->head)>0) temp+ = df->b(i)*df->u(df->head); else temp+ = df->b(i)*df->u(MAXSIZE;) }'' ''// For the denominator in the difference equeation '' ''for(i=1; ic=df->n; i++) {'' ''if((df->head)- i >= 0) temp- = df->a(i)*df->u(df->head); else temp- = df->a(i)*df->u(MAXSIZE); }'' ''} *Since the size of the buffer is not large enough, if we make a circular buffer Linux may crash. *Implementing the buffer as above requires much less coding than a dynamically linked-list. This means faster processing because the CPU handles less code. ='Exercise 2.1 – User Interface Construction'= *I used: pointer = (volatile int*)mbuff_alloc(“tag”, 4); '' ''scanf(“%d”, pointer) inp => value -> &inp => pointer np => value -> inp => pointer john = (inp*4095)/100 changes a percentage to a speed *The user interface and “rtsample.c” will be sharing data through shared memory. *In “ui.c”, I must always do mbuff_free(“tag”, (void*) john); ='Exercise 2.2 – Driving the Motor'= *Using ‘a’ (writing data to the motor), 0'' (channel 0) and ''*jt ''(the value), ''0x5411 (‘a’, 0, *jt); is added to “0x5411.c” for the D/A converter. *I set 100,000,000ns = 0.1s. *I placed 0x5411(‘a’, 0, 0); in cleanup_module to step the motor when the real-time thread is removed from the kernel. *The real-time thread can’t handle floating-point numbers by default. So, I placed pthread_setfp_np(pthread_self( ), 1); before the while ''loop. ='Exercise 2.3 – Real Time Data Acquisition'= *Here we use an A/D converter to read values from the motor and graph them on Linux. *Used ''0x5411(‘m’, 0, 0);, where ‘m’ = reading, 0'' = channel 0. Note that the second 0 is ambiguous when operating in this mode. *The output is in the range 0…4095, which I changed to a percentage using ''jth = ((*chan)*100)/4095; *To graph the readings from the motor, I added CDSM_init( ); in init_module, CDSM_done; in cleanup_module, and CDSM_set(0, value); in the while loop. Note value is set by filtered_pos, after filtering. *''jth'' = the percentage value, is filtered using a low-pass filter. filtered_pos = ((10-alpha)*jth(alpha)*prev_filtered_pcs)/10;. '' Can’t use floating-point numbers, but ''alpha must be in decimals. To remedy this situation, I multiply alpha by 10 to get integer values. So the 1 in y(t) becomes 10. After all operations, alpha is divided by 10 to once again get a decimal. *Following that, I put prev_filtered_pc5 = filtered_pos; *''alpha'' was predicted to be in the range 3…7. *The results from filtering were: *If the frequency is high, giving alpha a high value resulted in filtering the original frequency. *If alpha was low, I could still pass low frequencies. Hence, no significant filtering was happening. *I found that to a certain limit, the higher I set the sampling rate, the smoother the result I got. *I observed the following: (3a) Only the green lined moved. #The blue line moved slightly, which passed the green line. The purple line also moved. #When setting P=3.5 and I=7.3, oscillation occurred. #Increasing P decreased response time, but increased overshoot. #A good response time was achieved with D=1. *Although part of the control system is run in real-time, the calculations are not performed periodically. This problem is significant since the calculations have to be done in real-time. Hence, this is not a true real-time system. *The process thread is periodic, which stores simulated data in cont =>'' sim_data''. The data and control threads are not periodic, that is, they are not in real-time. As a result, the program suspends them. This is apparent when the control thread wakes up the data thread after it has done the calculations. *Data is accessed by the threads through the shared memory structure. *Thread synchronisation is achieved when sample wakes up control. *Some improvements to the system would include performing calculations periodically to ensure proper real-time performance. Also, the system would be easier to use if vxscope was integrated into the GUI. Category:ELEC2142